#define ZCORE_SOURCE
#include "StringTools.hpp"

namespace zzz{
string Replace(const string &ori, const string &from, const string &to) {
  string ret;
  zuint i=0;
  while(i<ori.size()) {
    int x=ori.find(from, i);
    if (x==string::npos) {
      ret.append(ori.begin()+i,ori.end());
      break;
    }
    ret.append(ori.begin()+i,ori.begin()+i+x);
    ret.append(to.begin(),to.end());
    i+=x;
    i+=from.size();
  }
  return ret;
}
  
  
//////////////////////////////////////////////////
//Ideas taken from work done by Bob Withers
//2002-05-07 by Markus Ewald
void Base64Encode(const string &data, zsize size, string &sResult) {
  static const std::string sBase64Table(
    // 0000000000111111111122222222223333333333444444444455555555556666
    // 0123456789012345678901234567890123456789012345678901234567890123
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
  );
  static const char cFillChar = '=';
  zuint nLength = size;
  sResult.clear();
  // Allocate memory for the converted string
  sResult.reserve(nLength * 8 / 6 + 1);

  for(zuint nPos = 0; nPos < nLength; nPos++) {
    char cCode;

    // Encode the first 6 bits
    cCode = (data[nPos] >> 2) & 0x3f;
    sResult.append(1, sBase64Table[cCode]);

    // Encode the remaining 2 bits with the next 4 bits (if present)
    cCode = (data[nPos] << 4) & 0x3f;
    if(++nPos < nLength)
      cCode |= (data[nPos] >> 4) & 0x0f;
    sResult.append(1, sBase64Table[cCode]);

    if(nPos < nLength) {
      cCode = (data[nPos] << 2) & 0x3f;
      if(++nPos < nLength) cCode |= (data[nPos] >> 6) & 0x03;
      sResult.append(1, sBase64Table[cCode]);
    } else {
      ++nPos;
      sResult.append(1, cFillChar);
    }

    if(nPos < nLength) {
      cCode = data[nPos] & 0x3f;
      sResult.append(1, sBase64Table[cCode]);
    } else {
      sResult.append(1, cFillChar);
    }
  }
}

int Base64Decode(const string &sString, char *data, const zsize size) {
  static const std::string::size_type np = std::string::npos;
  static const std::string::size_type DecodeTable[] = {
    // 0   1   2   3   4   5   6   7   8   9 
    np, np, np, np, np, np, np, np, np, np,  //   0 -   9
    np, np, np, np, np, np, np, np, np, np,  //  10 -  19
    np, np, np, np, np, np, np, np, np, np,  //  20 -  29
    np, np, np, np, np, np, np, np, np, np,  //  30 -  39
    np, np, np, 62, np, np, np, 63, 52, 53,  //  40 -  49
    54, 55, 56, 57, 58, 59, 60, 61, np, np,  //  50 -  59
    np, np, np, np, np,  0,  1,  2,  3,  4,  //  60 -  69
    5,  6,  7,  8,  9, 10, 11, 12, 13, 14,  //  70 -  79
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24,  //  80 -  89
    25, np, np, np, np, np, np, 26, 27, 28,  //  90 -  99
    29, 30, 31, 32, 33, 34, 35, 36, 37, 38,  // 100 - 109
    39, 40, 41, 42, 43, 44, 45, 46, 47, 48,  // 110 - 119
    49, 50, 51, np, np, np, np, np, np, np,  // 120 - 129
    np, np, np, np, np, np, np, np, np, np,  // 130 - 139
    np, np, np, np, np, np, np, np, np, np,  // 140 - 149
    np, np, np, np, np, np, np, np, np, np,  // 150 - 159
    np, np, np, np, np, np, np, np, np, np,  // 160 - 169
    np, np, np, np, np, np, np, np, np, np,  // 170 - 179
    np, np, np, np, np, np, np, np, np, np,  // 180 - 189
    np, np, np, np, np, np, np, np, np, np,  // 190 - 199
    np, np, np, np, np, np, np, np, np, np,  // 200 - 209
    np, np, np, np, np, np, np, np, np, np,  // 210 - 219
    np, np, np, np, np, np, np, np, np, np,  // 220 - 229
    np, np, np, np, np, np, np, np, np, np,  // 230 - 239
    np, np, np, np, np, np, np, np, np, np,  // 240 - 249
    np, np, np, np, np, np                   // 250 - 256
  };
  static const char cFillChar = '=';

  zuint nLength = sString.size();
  zuint cur=0;
  if (size==0) return 0;
  for(zuint nPos = 0; nPos < nLength; nPos++) {
    unsigned char c, c1;

    c = (char) DecodeTable[(unsigned char)sString[nPos]];
    nPos++;
    c1 = (char) DecodeTable[(unsigned char)sString[nPos]];
    c = (c << 2) | ((c1 >> 4) & 0x3);
    data[cur++]=c;
    if (cur==size) break;

    if(++nPos < nLength) {
      c = sString[nPos];
      if(cFillChar == c) break;
      c = (char) DecodeTable[(unsigned char)sString[nPos]];
      c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
      data[cur++]=c1;
      if (cur==size) break;
    }
    if(++nPos < nLength) {
      c1 = sString[nPos];
      if(cFillChar == c1) break;
      c1 = (char) DecodeTable[(unsigned char)sString[nPos]];
      c = ((c << 6) & 0xc0) | c1;
      data[cur++]=c;
      if (cur==size) break;
    }
  }
  return cur;
}

const string BlankChars = " \t\n\r\x0B";
string TrimFront(const string &str, const string &c/*=BlankChars*/) {
  if (str.empty()) return string();
  int len=str.size();
  int startpos;
  for (startpos=0;startpos<len;startpos++) {
    char now=str[startpos];
    if (find(c.begin(), c.end() ,now)!=c.end()) continue;
    break;
  }
  string temp(str.begin()+startpos,str.end());
  return temp;
}

string TrimBack(const string &str, const string &c/*=BlankChars*/) {
  if (str.empty()) return string();
  int len=str.size();
  int endpos;
  for (endpos=len-1;endpos>=0;endpos--) {
    char now=str[endpos];
    if (find(c.begin(), c.end() ,now)!=c.end()) continue;
    break;
  }
  string temp(str.begin(),str.begin()+endpos+1);
  return temp;
}

string Trim(const string &str, const string &c/*=BlankChars*/) {
  if (str.empty()) return string();
  int len=str.size();
  int startpos,endpos;
  for (startpos=0;startpos<len;startpos++) {
    char now=str[startpos];
    if (find(c.begin(), c.end() ,now)!=c.end()) continue;
    break;
  }
  for (endpos=len-1;endpos>=0;endpos--) {
    char now=str[endpos];
    if (find(c.begin(), c.end() ,now)!=c.end()) continue;
    break;
  }
  if (endpos<=startpos) {
    return string();
  }
  string temp(str.begin()+startpos,str.begin()+endpos+1);
  return temp;
}

void SplitString(const string &str, vector<string> &ret, const char splitchar) {
  ret.clear();
  string tmp;
  for (string::const_iterator si=str.begin();si!=str.end();si++) {
    if (*si == splitchar && !tmp.empty()) {
      ret.push_back(tmp);
      tmp.clear();
      continue;
    }
    tmp.push_back(*si);
  }
  if (!tmp.empty())
    ret.push_back(tmp);
}

void JoinString(const vector<string> &strs, string &ret, const char joinchar) {
  ret.clear();
  if (strs.empty()) return;
  ret = strs[0];
  for (zuint i=1; i<strs.size(); i++) {
    ret += joinchar;
    ret += strs[i];
  }
}

string JoinCmd(int argc, char *argv[]) {
  string ret = argv[0];
  for (int i=1; i<argc; i++) {
    if (find(argv[i],argv[i]+strlen(argv[i]), ' ') !=
        argv[i]+strlen(argv[i])) {
      ret += " \"";
      ret += argv[i];
      ret += "\"";
    }
    else
    {
      ret += ' ';
      ret += argv[i];
    }
  }
  return ret;
}

string RandomString(int length, bool letters, bool numbers, bool symbols) {
  // the shortest way to do this is to create a string, containing
  // all possible values. Then, simply add a random value from that string
  // to our return value
  std::string allPossible; // this will contain all necessary characters
  std::string str; // the random string
  if (letters) { // if you passed true for letters, we'll add letters to the possibilities
    allPossible += "abcdefghijklmnopqrstuvwxyz";
    allPossible += "ABCDEFGHIJKLMNOPQRSUTVWXYZ";
  }
  if (numbers) { // if you wanted numbers, we'll add numbers
    allPossible += "0123456789";
  }
  if (symbols) { // if you want symbols, we'll add symbols (note, their ASCII values are scattered)
    allPossible += "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~";
  }
  // get the number of characters to use (used for rand())
  int numberOfPossibilities = allPossible.length();
  for (int i = 0; i < length; i++) {
    str += allPossible[rand() % numberOfPossibilities];
  }

  return str;
}

}